package com.copm.ifm.common.generate.builder;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.copm.ifm.base.api.pojo.BasePO;
import com.copm.ifm.common.generate.config.GeneratorConfig;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * CodeGenerator
 *
 * @author Achin
 * @create 2019-01-11 11:28
 */
public class CodeGenerator {

    /**
     * 项目根路径，不包含项目名
     */
    private static final String PROJECT_PATH = new File(CodeGenerator.class.getResource("/").getPath())
            .getParentFile().getParentFile().getParentFile().getParentFile().getAbsolutePath().replace("\\", "/");


    public static void generator(GeneratorConfig myConfig) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        // 输出目录[后面自定义各个文件的输出路径]
        //gc.setOutputDir(projectPath + "/src/main/java");
        // 生成者
        gc.setAuthor(myConfig.getAuthor());
        // 生成后打开文件夹
        gc.setOpen(false);
        // 是否覆盖文件
        gc.setFileOverride(true);
        // 开启 swagger2 模式
        gc.setSwagger2(true);
        // 开启 activeRecord 模式
        //gc.setActiveRecord(true);
        // XML 二级缓存
        //gc.setEnableCache(true);
        // XML ResultMap
        gc.setBaseResultMap(true);
        // XML columList
        gc.setBaseColumnList(true);
        // 自定义文件命名，注意 %s 会自动填充表实体属性！
//        if (myConfig.getIncludeTable().startsWith(myConfig.getModuleName()+"_")){
//            gc.setMapperName("%sMapper");
//            gc.setXmlName("%sMapper");
//            gc.setServiceName("%sService");
//            gc.setServiceImplName("%sServiceImpl");
//            gc.setControllerName("%sController");
//            gc.setEntityName("%s");
//        }else {
//            String moduleName = myConfig.getModuleName().substring(0,1).toUpperCase() + myConfig.getModuleName().substring(1);
//            gc.setMapperName(moduleName + "%sMapper");
//            gc.setXmlName(moduleName + "%sMapper");
//            gc.setServiceName(moduleName + "%sService");
//            gc.setServiceImplName(moduleName + "%sServiceImpl");
//            gc.setControllerName(moduleName + "%sController");
//            gc.setEntityName(moduleName + "%s");
//        }
        gc.setMapperName("%sMapper");
        gc.setXmlName("%sMapper");
        gc.setServiceName("%sService");
        gc.setServiceImplName("%sServiceImpl");
        gc.setControllerName("%sController");
        gc.setEntityName("%s");
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        // dsc.setSchemaName("public");
        dsc.setDriverName(myConfig.getDriverName());
        dsc.setUrl(myConfig.getUrl());
        dsc.setUsername(myConfig.getUsername());
        dsc.setPassword(myConfig.getPassword());
        dsc.setDbType(myConfig.getDbType());

        //字段类型转换
        dsc.setTypeConvert((globalConfig, t) -> {
            if (t.contains("char") || t.contains("text")) {
                return DbColumnType.STRING;
            } else if (t.contains("bigint")) {
                return DbColumnType.LONG;
            } else if (t.contains("int")) {
                return DbColumnType.INTEGER;
            } else if (t.toUpperCase().equals("TIMESTAMP")) {
                return DbColumnType.LOCAL_DATE_TIME;
            } else if (t.contains("date") || t.contains("time") || t.contains("year")) {
                return DbColumnType.DATE;
            } else if (t.contains("bit")) {
                return DbColumnType.BOOLEAN;
            } else if (t.contains("decimal")) {
                return DbColumnType.BIG_DECIMAL;
            } else if (t.contains("clob")) {
                return DbColumnType.CLOB;
            } else if (t.contains("blob")) {
                return DbColumnType.BLOB;
            } else if (t.contains("binary")) {
                return DbColumnType.BYTE_ARRAY;
            } else if (t.contains("float")) {
                return DbColumnType.FLOAT;
            } else if (t.contains("double")) {
                return DbColumnType.DOUBLE;
            } else if (t.contains("json") || t.contains("enum")) {
                return DbColumnType.STRING;
            } else if (t.toLowerCase().equals("localdatetime")) {
                return DbColumnType.DATE;
            }
            return DbColumnType.valueOf(t);
        });

        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        //pc.setModuleName(myConfig.getModuleName());
        pc.setParent(myConfig.getParent());
        pc.setEntity(myConfig.getEntityPackage());
        pc.setMapper(myConfig.getMapperPackage());
        pc.setService(myConfig.getServicePackage());
        pc.setServiceImpl(myConfig.getServiceImplPackage());
        pc.setController(myConfig.getControllerPackage());
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        //自定义文件输出位置
        List<FileOutConfig> focList = new ArrayList<>();
        //自定义mapper.xml的输出位置
        definedPath(myConfig.getMapperXml(), focList, "/generator/templates/mapper.xml.ftl", myConfig.getMapperXmlPath(), "Mapper", StringPool.DOT_XML);
        //自定义mapper的输出路径
        definedPath(myConfig.getMapper(), focList, "/templates/mapper.java.ftl", myConfig.getMapperPath(), "Mapper", StringPool.DOT_JAVA);
        //自定义service的输出路径
        definedPath(myConfig.getService(), focList, "/templates/service.java.ftl", myConfig.getServicePath(), "Service", StringPool.DOT_JAVA);
        //自定义serviceImpl的输出路径 [使用自定义serviceImpl模板输出]
        definedPath(myConfig.getServiceImpl(), focList, "/generator/templates/serviceImpl.java.ftl", myConfig.getServiceImplPath(), "ServiceImpl", StringPool.DOT_JAVA);
        //自定义controller的输出路径
        definedPath(myConfig.getController(), focList, "/templates/controller.java.ftl", myConfig.getControllerPath(), "Controller", StringPool.DOT_JAVA);
        //自定义entity的输出路径 [使用自定义entity模板输出]
        definedPath(myConfig.getEntity(), focList, "/generator/templates/entity.java.ftl", myConfig.getEntityPath(), "", StringPool.DOT_JAVA);
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        // 关闭默认 文件 生成，调整生成 至 自定义目录
        mpg.setTemplate(new TemplateConfig()
                .setXml(null)
                .setMapper(null)
                .setService(null)
                .setServiceImpl(null)
                .setController(null)
                .setEntity(null)
        );

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setSuperServiceClass(IService.class);
        strategy.setSuperServiceImplClass(ServiceImpl.class);
        strategy.setSuperMapperClass("com.baomidou.mybatisplus.core.mapper.BaseMapper");
        strategy.setSuperControllerClass("import com.copm.ifm.base.service.base.BaseController");
        strategy.setEntityLombokModel(true);
        strategy.setSuperEntityClass(BasePO.class);
        strategy.setRestControllerStyle(true);
        strategy.setInclude(myConfig.getIncludeTable());
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());

        mpg.execute();
    }

    public static void definedPath(Boolean flag,
                                   List<FileOutConfig> focList,
                                   String templates,
                                   String filePath,
                                   String fileName,
                                   String dot) {
        if (flag) {
            focList.add(new FileOutConfig(templates) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输入文件名称
                    return PROJECT_PATH + filePath + "/" + tableInfo.getEntityName() + fileName + dot;
                }
            });
        }
    }

    public static String packagePath(String packageStr) {
        return "".equals(packageStr) ? packageStr : ("." + packageStr);
    }

}
